读书笔记: 《Android 开发艺术探索》 ——第十章:android 消息机制
对于 android 中的消息机制,主要是指 Handler 的运行机制。在我们平时的开发中 ,对它并不陌生。由于android 是 单线程(UI线程)机制,对于一些耗时操作会在子线程中进行,如文件读取等.
往往在操作完成后会有 UI 的更新,由于 android 中不允许在子线程中更新ui,所以我们 常常用 Handler 来更新UI ,但它的功能不仅仅如此。
一、消息机制概述
Handler
的运行 需要底层的 MessageQueue 和 Looper 支撑。MessageQueue
是指消息队列,在他内部存储了一组消息,以队列的形式对外提供增删。虽名为队列,但是其内部的实现是采用 单链表。Looper
主要是用于消息循环,他内部通过无线循环的方式,查看是否有消息,如果有就处理,否则阻塞等待着。 在 Looper 中 利用 ThreadLocal
进行存储数据,它可以保证各个线程中互不干扰的存储和提供数据。
如果 使用 Handler 就必须为线程创建 Looper。我们能够在 Activity 只用它,主要是应为在 UI 线程( ActivityThread ) 创建是会初始化 looper。
android 系统不允许 在子线程中访问UI ,主要是 很多控件时线程不安全的,如果多线程并发访问会出现不可预期的效果;同时由于 锁机制会让 UI 访问逻辑变复杂,并且会阻塞某些线程从而降低 UI 访问效率,并没有对 UI 线程进行加锁 操作。
如下是 Handler 的 工作过程:
说明:首先 Handle 通过 sendMessage()
等方法发送一个消息,最终会调用 MessageQueue 的 enqueueMessage 方法 将消息添加到消息队列中;而 Looper 的 loop方法发现新消息后,从队列中取出消息,最后将其转发到 Handle 中,最终在 handleMessage 进行处理。而Looper 是运行在创建handler 的线程中,这样将Handler 中的业务逻辑切换到 穿件 Handler 的线程中去了。
二、消息机制分析
2.1 ThreadLocal 的工作原理
ThreadLocal 主要是线程内部的数据存储类,他可以在指定的线程中存储数据,然后只有指定的线程可以获取。,而其他线程则无法获取。这里使用它 可以方便的实现 Looper 在线程中的存取,此外,他还可以在复杂的逻辑下进行对象的传递,如监听器的传递。
由于 api23 前后,ThreadLocal 的内部实现不同,这里不具体介绍。
2.2 MessageQueue 的工作原理
在消息队列 MessageQueue 中主要包括两个操作:插入和读取,在读取的同时伴随有删除。 插入和读取分别对应于 enqueueMessage
和 next
。 enqueueMessage 是往队列中插入 一条数据,采用非的是单链表的插入操作,其内部采用了锁机制,而 next 是一个无限循环方法,若无消息,那么它将阻塞者,若有消息,则返回该消息并将其从消息队列中移除。
2.3 Looper 的工作原理
Looper 是消息循环的角色,不停的从 MessageQueue 中取消息,若存在则立即处理,否则阻塞。在 Looper 的构造方法中会创建一个MessageQueue对象。
Handle 的工作需要 looper ,如果没有回报错,可以用 prepare
方法创建Looper:
1 2 3 4 5
| // 创建looper Looper.prepare(); //.... //开启循环 Looper.loop();
|
才外,还提供了 prepareMainLooper
方法为主线程创建Looper。对于退出循环,则提供了 quit
和 quitSafely
方法,前者是直接退出,后者则是设置个退出标记,等消息处理完后再退出。
通常在子线程中创建的looper ,在执行完后应该退出,当执行退出后,次线程会立即终止,若handler 再次发送消息,则会返回 false。
由于在 Looper 的 loop 方法中调用用了 MessageQueue 的 next方法,而next 方法是个阻塞的,导致loop阻塞。如下loop方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
| public static void loop() { final Looper me = myLooper(); if (me == null) { throw new RuntimeException ("No Looper; Looper.prepare() wasn't called on this thread."); } final MessageQueue queue = me.mQueue; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; //... final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled (traceTag) ) { Trace.traceBegin (traceTag, msg.target.getTraceName (msg) ); } try { msg.target.dispatchMessage (msg); } finally { if (traceTag != 0) { Trace.traceEnd (traceTag); } } //... // Make sure that during the course of dispatching the // identity of the thread wasn't corrupted. final long newIdent = Binder.clearCallingIdentity(); //... msg.recycleUnchecked(); } }
|
注意 msg.target.dispatchMessage (msg);
一句,msg是一个从MessageQueue 中取出的Message对象,而 target 则是 Message 中的一个 Handler 类型的 成员变量,这样使得 loop方法将消息队列中的消息分发给 Handler 进行处理。
2.4 Handler 的工作原理
handler 主要包括消息的发送和接受,主要包括一系列的post和send方法实现的,而post最终是通过 send实现的。如下各个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); } public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); } public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageAtTime(msg, uptimeMillis); } public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); } public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); } private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
|
通过上面的各个方法,最终是往调用了 enqueueMessage 方法 往 MessageQueue 中插入一条消息。在Looper 中 调用了 MessageQueue 的next 方法,取出一条消息,通过 dispatchMessage 方法将消息分发给 Handler 处理,如下其具体实现:
1 2 3 4 5 6 7 8 9 10 11 12
| public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
|
这里首先检查 callback 是否为null,不为空就调用 handleCallback 处理,它是一个 Runnable对象;其次检查 mCallback 是否为null ,mCallback 是一个Callback类型的接口,内部只有一个方法:
1 2 3
| public interface Callback { public boolean handleMessage(Message msg); }
|
这里的 Callback 可以用来创建 Handle 对象,常见的创建 Handler 是重写 handleMessage 方法。
如下 Handler 的消息处理流程:
三、主线程消息循环
主线程即ActivityThread ,其注入口方法为 main,在该方法中,通过 Looper.prepareMainLooper();
创建Looper,最后通过 Looper.loop();
开启消息循环。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public static void main (String[] args) { //... // 创建主线程的Looper Looper.prepareMainLooper(); ActivityThread thread = new ActivityThread(); thread.attach (false); if (sMainThreadHandler == null) { sMainThreadHandler = thread.getHandler(); } if (false) { Looper.myLooper().setMessageLogging (new LogPrinter (Log.DEBUG, "ActivityThread") ); } // End of event ActivityThreadMain. Trace.traceEnd (Trace.TRACE_TAG_ACTIVITY_MANAGER); //开启循环 Looper.loop(); throw new RuntimeException ("Main thread loop unexpectedly exited"); }
|
ActivityThread 的内部类 H 继承自 Handler ,其内部定义了一组消息类型,组要包括了四大组件的启动和停止。
主线程消息循环模型:ActivityThread 内部通过 ApplicationThread 和 AMS 进行进程间通信,AMS 以进程间通信的方式完成 ActivityThread 的请求后回调 ApplicationThread 中的 Binder 方法,然后 ApplicationThread 向 H 发送消息, H收到后将 ApplicationThread 中的逻辑切换到 ActivityThread 中去执行。
上一篇:AsyncTask 工作原理及线程池
下一篇:android 自定义View 详解